package wxwoa

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"time"

	"gitee.com/chenrh/finego/app"
	"gitee.com/chenrh/finego/backends/models"
	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/mvc"
)

// WxAuthorizeController 获得当前微信用户授权信息
type WxAuthorizeController struct {
	Ctx iris.Context

	// api site https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#0
	// 用户同意授权后
	// 如果用户同意授权，页面将跳转至 redirect_uri/?code=CODE&state=STATE。
	// 本项目统一检测授权验证：
	// redirect_uri = http://www.chenrh.com/wx/authorize
	// state = [指向地址]
}

// BeforeActivation Mvc 注册路由
func (c *WxAuthorizeController) BeforeActivation(b mvc.BeforeActivation) {
	b.Handle("GET", "/authorize", "GetUserAuthourizInfo")
}

// GetUserAuthourizInfo 如果用户同意授权，页面将跳转至 redirect_uri/?code=CODE&state=STATE。
func (c WxAuthorizeController) GetUserAuthourizInfo(ctx iris.Context) {
	//  code作为换取access_token的票据，每次用户授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期。
	code := ctx.URLParam("code")
	/*
		第二步：通过code换取网页授权access_token (此access_token 与公众号 access_token 不是同一个)
		首先请注意，这里通过code换取的是一个特殊的网页授权access_token,与基础支持中的access_token（该access_token用于调用其他接口）不同。
		公众号可通过下述接口来获取网页授权access_token。
		如果网页授权的作用域为snsapi_base，则本步骤中获取到网页授权access_token的同时，也获取到了openid，snsapi_base式的网页授权流程即到此为止。
		尤其注意：由于公众号的secret和获取到的access_token安全级别都非常高，必须只保存在服务器，不允许传给客户端。
		后续刷新access_token、通过access_token获取用户信息等步骤，也必须从服务器发起。
		请求方法
		获取code后，请求以下链接获取access_token： https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
	*/
	appid := WeChatSubscriptionAppID(c.Ctx)
	appsecret := WeChatSubscriptionAppSecret(c.Ctx)
	url := "https://api.weixin.qq.com/sns/oauth2/access_token?"
	url += fmt.Sprintf("appid=%s", appid)
	url += fmt.Sprintf("&secret=%s", appsecret)
	url += fmt.Sprintf("&code=%s", code)
	url += "&grant_type=authorization_code"

	resp, err := http.Get(url)
	if err != nil {
		app.LoggerWithCtx(ctx).Errorf(err.Error())
		log.Println("出现错误：", err.Error())
		return
	}
	defer resp.Body.Close()

	body, _ := ioutil.ReadAll(resp.Body)
	content := string(body)
	/*
		    如果正确时返回
			{
			"access_token":"ACCESS_TOKEN",
			"expires_in":7200,
			"refresh_token":"REFRESH_TOKEN",
			"openid":"OPENID",
			"scope":"SCOPE"
			}
			否则
			{"errcode":40029,"errmsg":"invalid code"}
	*/

	var jsonmap map[string]interface{}
	json.Unmarshal([]byte(content), &jsonmap)

	if _, ok := jsonmap["access_token"]; ok {

		m := models.WX_AUTHORIZE{}

		/*
			参数			说明
			access_token	获取到的凭证
			expires_in		凭证有效时间，单位：秒
		*/
		m.Code = code
		m.AccessToken = jsonmap["access_token"].(string)
		m.ExpiresIn = jsonmap["expires_in"].(float64)
		m.RefreshToken = jsonmap["refresh_token"].(string)
		m.OpenID = jsonmap["openid"].(string)
		t := time.Now().Add(time.Duration(m.ExpiresIn) * time.Second)
		m.ExpiresAt = &t
		app.GetDB().Create(&m)

		state := ctx.URLParam("state")
		ctx.Redirect(state + "?openid=" + m.OpenID)

	} else if _, ok := jsonmap["errcode"]; ok {

		c.Ctx.JSON(jsonmap)
		// return return mvc.Response{Err: errors.New("此代码可能有误，未查到对应股票"), Code: 200}
	}

	c.Ctx.JSON(content)
}
